<template>
	<el-select clearable fit-input-width :filterable="filter" :remote="filter" :multiple="multiple" :disabled="disabled"
		:value-key="valueKey" :placeholder="placeholder" :remote-method="filterHandle" v-model="retuenValue"
		@change="onChange" remote-show-suffix>
		<el-option v-for="(item, index) in optionsList" :key="item[valueKey]" :label="item[labelKey]" :value="item[valueKey]">
			<slot v-bind="item" :$row="item" :$index="index">
				{{ item[labelKey] }}
			</slot>
		</el-option>
	</el-select>
</template>

<script setup>
import { computed, ref, watch } from "vue"
import { findPinYin } from "/plugins/pinyin"
import { useDictStore } from "/store/dict"

const props = defineProps({
	modelValue: {
		type: [String, Number, Array],
		default: "",
	},
	placeholder: {
		type: String,
		default: "请选择...",
	},
	multiple: {
		type: Boolean,
		default: false,
	},
	dict: {
		type: [String, Array],
	},
	label: {
		type: String,
	},
	value: {
		type: String,
	},
	disabled: {
		type: Boolean,
		default: false,
	},
	filter: {
		type: Boolean,
		default: true,
	},
	filterMethod: {
		type: Function,
	},
	spacer: {
		type: String,
		default: ",",
	},
	join: {
		type: String,
	},
})

const emits = defineEmits(["update:modelValue", "change"])
const retuenValue = computed({
	get() {
		if (props.modelValue === null || props.modelValue === undefined || props.modelValue === "") {
			return props.multiple ? [] : ""
		}
		if (Array.isArray(props.modelValue)) {
			return props.modelValue.map(item => item + "")
		} else {
			if (props.multiple) {
				return (props.modelValue + "").split(props.spacer)
			} else {
				return props.modelValue + ""
			}
		}
	},
	set(value) {
		if (Array.isArray(value)) {
			if (props.join || props.spacer) {
				value = value.join(props.join || props.spacer)
			}
			emits("update:modelValue", value)
		} else {
			emits("update:modelValue", value)
		}
	},
})
const labelKey = computed(() => {
	if (props.label) {
		return props.label
	}
	return "name"
})
const valueKey = computed(() => {
	if (props.value) {
		return props.value
	}
	return "code"
})
const optionsList = ref([])
function refreshOptionsList() {
	if (typeof props.dict === "string") {
		const dictStore = useDictStore()
		dictStore.getDict(props.dict).then(resule => {
			optionsList.value = resule.map(item => ({ ...item, [valueKey.value]: item[valueKey.value] + "" }))
		})
		return
	}
	optionsList.value = props.dict.map(item => ({ ...item, [valueKey.value]: item[valueKey.value] + "" }))
}
refreshOptionsList()
let curList = optionsList.value
async function filterHandle(query) {
	if (query === "" || query === null) {
		return curList
	}
	if (props.filterMethod) {
		const result = await props.filterMethod(query, curList)
		optionsList.value = result
	} else {
		optionsList.value = curList.filter(item => findPinYin(item[labelKey.value], query))
	}
}

watch(
	() => props.dict,
	() => {
		if (!props.dict) {
			return
		}
		refreshOptionsList()
		curList = optionsList.value
	},
	{
		deep: true,
	}
)

function onChange(value) {
	emits("change", value)
}
</script>

<style lang="scss" scoped></style>
